package com.cetcs.kmga.dataManager.service.impl.dataManager;

import com.cetc.cloud.kmga.util.DateUtils;
import com.cetc.cloud.kmga.util.EmailManager;
import com.cetcs.kmga.common.Constant;
import com.cetcs.kmga.common.Data;
import com.cetcs.kmga.common.Page;
import com.cetcs.kmga.dataManager.dao.mybatis.*;
import com.cetcs.kmga.dataManager.entity.dataManager.Resrc;
import com.cetcs.kmga.dataManager.entity.dataManager.RiskEvent;
import com.cetcs.kmga.dataManager.entity.dataManager.vi.RiskEventMqVi;
import com.cetcs.kmga.dataManager.entity.dataManager.vo.CircularChartVo;
import com.cetcs.kmga.dataManager.entity.dataManager.vo.FlipHistogramChartVo;
import com.cetcs.kmga.dataManager.entity.dataManager.vo.MultiLineChartVo;
import com.cetcs.kmga.dataManager.entity.dataManager.vo.RiskEventVo;
import com.cetcs.kmga.dataManager.entity.device.SecuRule;
import com.cetcs.kmga.dataManager.entity.device.vo.KeyAndValueVo;
import com.cetcs.kmga.dataManager.entity.global.HistogramChart;
import com.cetcs.kmga.dataManager.entity.global.PieChart;
import com.cetcs.kmga.dataManager.entity.global.PolygonalGraph;
import com.cetcs.kmga.dataManager.entity.sysManager.SysEmailSerConf;
import com.cetcs.kmga.dataManager.service.dataManager.RiskEventService;
import com.cetcs.kmga.dataManager.service.feature.FeatureCodeService;
import com.cetcs.kmga.dataManager.service.sysManager.SysManagerService;
import com.cetcs.kmga.dataManager.util.CommonUtils;
import com.cetcs.kmga.dataManager.util.ConsumerMqUtil;
import com.cetcs.kmga.dataManager.util.JsonUtil;
import com.cetcs.kmga.dataManager.util.ReadConfigUtil;
import com.cetcs.kmga.dataManager.util.socket.MsgService;
import com.cetcs.kmga.dataManager.util.socket.SocketResponse;
import com.cetcs.kmga.dataManager.util.socket.SocketType;
import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import com.github.miemiedev.mybatis.paginator.domain.PageList;
import com.google.common.collect.Lists;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * 风险事件服务层实现类
 *
 * @author zhangchunkin
 * @version V1.0 创建时间：2017-10-10 10:05
 *          Copyright 2017 by CETC
 */
@Service
public class RiskEventServiceImpl implements RiskEventService {

    private final static Logger LOGGER = LoggerFactory.getLogger(RiskEventServiceImpl.class);
    @Autowired
    private RiskEventMapper riskEventMapper;

    @Autowired
    private SecuRuleMapper secuRuleMapper;

    @Autowired
    private AuditManagerMapper auditManagerMapper;

    @Autowired
    private FeatureCodeService featureCodeService;

    @Autowired
    private SysManagerService sysManagerService;

    @Autowired
    private MsgService msgService;

    /**
     * 风险概况
     *
     * @param startDate
     * @param endDate
     * @return
     */
    @Override
    public MultiLineChartVo findEventStatistics(String startDate, String endDate, List<String> xData) {
        MultiLineChartVo ret = new MultiLineChartVo( );
        //获取动态数据
        Data dataMap = new Data( );
        dataMap.put("startDate", startDate);
        dataMap.put("endDate", endDate);
        List<PolygonalGraph> polygonalGraphas = riskEventMapper.findEventStatistics(dataMap);
        //封装 X轴数据 y轴数据
        if (polygonalGraphas.size( ) > 0) {
            ret.setName("风险事件统计");
            ret.setxAxis(xData);
            List<String> titles = Arrays.asList("高风险", "中风险", "低风险");
            List<String> highRisk = Lists.newArrayList( );
            List<String> midRisk = Lists.newArrayList( );
            List<String> lowRisk = Lists.newArrayList( );
            List<String> generalRisk = Lists.newArrayList( );
            //现将数据通过日期
            Map<String, List<PolygonalGraph>> map = new LinkedHashMap<String, List<PolygonalGraph>>( );
            CommonUtils.listGroup2Map(polygonalGraphas, map, PolygonalGraph.class, "getxData");// 输入方法名
            for (String xTemp : xData) {
                if (map.containsKey(xTemp)) {
                    //表示有这个坐标的数据 转化为map
                    Map<String, List<PolygonalGraph>> mapObj = new LinkedHashMap<String, List<PolygonalGraph>>( );
                    CommonUtils.listGroup2Map(map.get(xTemp), mapObj, PolygonalGraph.class, "getName");// 输入方法名
                    if (mapObj.containsKey("高风险")) {
                        highRisk.add(mapObj.get("高风险").get(0).getyData( ));
                    } else {
                        highRisk.add("0");
                    }
                    if (mapObj.containsKey("中风险")) {
                        midRisk.add(mapObj.get("中风险").get(0).getyData( ));
                    } else {
                        midRisk.add("0");
                    }
                    if (mapObj.containsKey("低风险")) {
                        lowRisk.add(mapObj.get("低风险").get(0).getyData( ));
                    } else {
                        lowRisk.add("0");
                    }
                } else {
                    //没有这个数据
                    highRisk.add("0");
                    midRisk.add("0");
                    lowRisk.add("0");
                    generalRisk.add("0");
                }
            }
            List<MultiLineChartVo.YdataFormat> ydataFormats = Lists.newArrayList( );
            MultiLineChartVo.YdataFormat ydataFormat1 = new MultiLineChartVo.YdataFormat( );
            ydataFormat1.setName("高风险");
            ydataFormat1.setData(highRisk);
            ydataFormats.add(ydataFormat1);
            MultiLineChartVo.YdataFormat ydataFormat2 = new MultiLineChartVo.YdataFormat( );
            ydataFormat2.setName("中风险");
            ydataFormat2.setData(midRisk);
            ydataFormats.add(ydataFormat2);
            MultiLineChartVo.YdataFormat ydataFormat3 = new MultiLineChartVo.YdataFormat( );
            ydataFormat3.setName("低风险");
            ydataFormat3.setData(lowRisk);
            ydataFormats.add(ydataFormat3);
            ret.setDatas(ydataFormats);
        } else {
            //如果没有动态数据 则显示静态
//            ret.setName("风险事件统计");
//            ret.setxAxis(TrafficStatisticServiceImpl.mockDateString(startDate, endDate));
//            List<String> titles = Arrays.asList("高风险", "一般风险", "低风险");
//            ret.setDatas(TrafficStatisticServiceImpl.mockDatas(titles, ret));
        }
        return ret;
    }


    @Override
    public CircularChartVo findRiskLevelStatistic(String startDate, String endDate) {
        CircularChartVo ret = new CircularChartVo( );
        Data dataMap = new Data( );
        dataMap.put("startDate", startDate);
        dataMap.put("endDate", endDate);
        List<PieChart> pieCharts = riskEventMapper.findRiskLevelStatistic(dataMap);
        ret.setName("风险级别");
        if (pieCharts.size( ) > 0) {
            //数据不为空则显示动态数据
            for (PieChart pieChart : pieCharts) {
                ret.addData(pieChart.getName( ), Double.valueOf(pieChart.getData( )), pieChart.getId( ));
            }
        } else {
            //如果没有动态数据 则显示静态
//            ret.addData("低风险", 23.8, "1");
//            ret.addData("高风险", 29.76, "2");
//            ret.addData("一般风险", 46.44, "3");
        }
        return ret;
    }

    @Override
    public FlipHistogramChartVo findRiskDataSourceStatistic(String startDate, String endDate, String type, Integer isLimit) {
        FlipHistogramChartVo ret = new FlipHistogramChartVo( );
        Data dataMap = new Data( );
        dataMap.put("startDate", startDate);
        dataMap.put("endDate", endDate);
        dataMap.put("isLimit", isLimit);
        if (type != null) {
            dataMap.put("type", type);
        }
        ret.setName("风险数据源");
        List<HistogramChart> histogramCharts = riskEventMapper.findRiskDataSourceStatistic(dataMap);
        histogramCharts.sort(new Comparator<HistogramChart>() {
            @Override
            public int compare(HistogramChart o1, HistogramChart o2) {
                return Integer.parseInt(o1.getData())-Integer.parseInt(o2.getData());
            }
        });
        if (histogramCharts.size( ) > 0) {
            List<String> xData = Lists.newArrayList( );
            List<String> yData = Lists.newArrayList( );
            for (HistogramChart histogramChart : histogramCharts) {
                xData.add(histogramChart.getData( ));
                yData.add(histogramChart.getName( ));
            }
            ret.setData(xData);
            ret.setYaxis(yData);
        } else {
//            List<String> xdata = Arrays.asList("300", "600", "900", "1200", "1500");
//            ret.setData(xdata);
//            ret.setYaxis(Arrays.asList("监管系统", "PL/SQL", "用户互动应用", "资源开放目录", "门户网站"));
        }
        return ret;
    }

    @Override
    public FlipHistogramChartVo findRiskIpStatistic(String startDate, String endDate, String type, Integer isLimit) {
        FlipHistogramChartVo ret = new FlipHistogramChartVo( );
        Data dataMap = new Data( );
        dataMap.put("startDate", startDate);
        dataMap.put("endDate", endDate);
        dataMap.put("isLimit", isLimit);
        if (type != null) {
            dataMap.put("type", type);
        }
        ret.setName("风险IP");
        List<HistogramChart> histogramCharts = riskEventMapper.findRiskIpStatistic(dataMap);
        histogramCharts.sort((v1,v2)-> Integer.parseInt(v1.getData())-Integer.parseInt(v2.getData()));
        if (histogramCharts.size( ) > 0) {
            List<String> xData = Lists.newArrayList( );
            List<String> yData = Lists.newArrayList( );
            for (HistogramChart histogramChart : histogramCharts) {
                xData.add(histogramChart.getData( ));
                yData.add(histogramChart.getName( ));
            }
            ret.setData(xData);
            ret.setYaxis(yData);
        } else {
//            List<String> xdata = Arrays.asList("300", "600", "900", "1200", "1500");
//            ret.setData(xdata);
//            ret.setYaxis(Arrays.asList("173.73.23.43", "120.29.23.4", "72.123.87.52", "21.172.12.27", "72.17.25.119"));
        }
        return ret;
    }

    /**
     * 首先获取事件消息，将消息的格式转换消息实体，
     * 其次将判定的规则详情取出，判定需要向哪儿转发消息
     * 最后入库
     *
     * @param msg
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    @Override
    public void operRiskEventMsg(String msg) throws Exception {
        //获取事件消息实体
        RiskEventMqVi mqVi = JsonUtil.readJson2Pojo(msg, RiskEventMqVi.class);
        RiskEvent riskEvent = new RiskEvent( );
        BeanUtils.copyProperties(riskEvent, mqVi);
        //往数据库中保存
        riskEvent.setAuditId(mqVi.getAuditObjId( ));
        riskEvent.setOperType(mqVi.getOpType( ));
        riskEventMapper.addRiskEventRecord(riskEvent);
        Data data = new Data( );
        data.put("id", riskEvent.getResrcId( ));
        Resrc resrc = auditManagerMapper.getResrcById(data);
        RiskEvent newRiskEvent = riskEvent;
        if (resrc != null) {
            newRiskEvent.setResrcId(resrc.getName( ));
        } else {
            newRiskEvent.setResrcId("其他");
        }
        //取出规则
        SecuRule secuRule = secuRuleMapper.findSecuRuleById(riskEvent.getRuleId( ));
        switch (riskEvent.getLevel( )) {
            case "4":
                riskEvent.setLevel("高");
                break;
            case "3":
                riskEvent.setLevel("中");
                break;
            case "2":
                riskEvent.setLevel("低");
                break;
            default:
                riskEvent.setLevel("低");
                break;
        }
        String operName = featureCodeService.acquireValueByCodeAndTypeId("3", riskEvent.getOperType( ));
        if (StringUtils.isNotBlank(operName)) {
            newRiskEvent.setOperType(operName);
        } else {
            newRiskEvent.setResrcId("其他");
        }
        // 取出规则之后根据需要发送的类型判断是否向大屏或发送邮件
        if (secuRule != null) {
            newRiskEvent.setRuleId(secuRule.getName( ));
            String alertWayStr = secuRule.getAlertWay( );
            if (StringUtils.isNotBlank(alertWayStr)) {
                //判断是否发送邮件,并且发送邮件的邮箱的号码不能为空
                if (alertWayStr.contains("0") && StringUtils.isNotBlank(secuRule.getReceiver( ))) {
                    KeyAndValueVo emsg = convertRiskMsg2Email(newRiskEvent);
                    SysEmailSerConf record = sysManagerService.findSysEmailConfig( );
                    EmailManager emailManager = new EmailManager(record.getHost( ),
                            record.getPort( ), record.getSenderNick( ), record.getFrom( ), record.getUserName( ), record.getPassword( ));
                    emailManager.sendMail(record.getFrom( ), secuRule.getReceiver( ), emsg.getKey( ), emsg.getValue( ));
                }
                //是否向大屏推送消息
                if (alertWayStr.contains("1")) {
                    Map<String, Object> msgMap = new HashMap<>( );
                    msgMap.put("id", newRiskEvent.getEventId( ));
                    msgMap.put("name", newRiskEvent.getResrcId( ));
                    msgMap.put("rank", newRiskEvent.getLevel( ));
                    msgMap.put("time", newRiskEvent.getTime( ));
                    msgMap.put("type", newRiskEvent.getOperType( ));
                    msgMap.put("ip", newRiskEvent.getClientIp( ));
                    List<Map<String, Object>> msgList = Lists.newArrayList( );
                    msgList.add(msgMap);
                    SocketResponse response = new SocketResponse(Constant.OK, msgMap);
                    String userId = "1";//没接入用户系统时默认传给用户1，以后改正
                    response.setSocketType(SocketType.SOCKET_DATA_MANAGER_ZYGL_TYPE);
                    String msgStr = JsonUtil.objectToJson(response);
                    msgService.publishMsg(userId, msgStr);
                }
            }
        }
//        else {
//            LOGGER.error("========事件规则不存在======");
//        }
    }

    /**
     * 组装向用户发送邮件信息的标题与内容
     *
     * @param riskEvent
     * @return
     */
    private KeyAndValueVo convertRiskMsg2Email(RiskEvent riskEvent) {
        String titleStr = "[" + riskEvent.getLevel( ) + "][" + riskEvent.getResrcId( ) + "]发生[" + riskEvent.getRuleId( ) + "]告警事件" + riskEvent.getTime( );
        //组装内容
        StringBuffer contentBuffer = new StringBuffer("您好！<br/>");
        contentBuffer.append(riskEvent.getTime( )).append("在资源[").append(riskEvent.getResrcId( ))
                .append("] 上发生[").append(riskEvent.getLevel( )).append("] 的告警事件，具体信息如下：<br>");
        contentBuffer.append("事件ID：").append(riskEvent.getEventId( )).append("<br>");
        contentBuffer.append("触发规则：").append(riskEvent.getEventId( )).append("<br>");
        contentBuffer.append("客户端IP：").append(riskEvent.getEventId( )).append("<br>");
        contentBuffer.append("资源名称：").append(riskEvent.getEventId( )).append("<br>");
        contentBuffer.append("操作类型：").append(riskEvent.getEventId( )).append("<br>");
        contentBuffer.append("发生时间：").append(riskEvent.getEventId( )).append("<br>");
        String url = ReadConfigUtil.getValueByKey("conf/shirocas.properties", "shiro.casService").replace("shiro-cas", "");
        contentBuffer.append("更详细的信息请登录监管平台进行查看,[").append(url).append("]").append("<br>");
        contentBuffer.append(" -------------------------------<br>");
        contentBuffer.append("云南公安网安大数据安全监管平台");
        contentBuffer.append(DateUtils.getTime( ));
        KeyAndValueVo msg = new KeyAndValueVo( );
        msg.setKey(titleStr);
        msg.setValue(contentBuffer.toString( ));
        return msg;
    }


    //=====================yyangs start====================


    /**
     * 风险事件排名-资源 分页
     *
     * @param params
     * @return
     * @throws Exception
     */
    @Override
    public Page findRiskDataSourceListsByPage(Data params) throws Exception {
        PageList<RiskEventVo> pageList = riskEventMapper.findRiskDataSourceListsByPage(params, new PageBounds(params.getInt("page"), params.getInt("pageSize")));
        return new Page(pageList);
    }

    /**
     * 风险事件排名-客户端IP 分页
     *
     * @param params
     * @return
     * @throws Exception
     */
    @Override
    public Page findRiskIPListsByPage(Data params) throws Exception {
        PageList<RiskEventVo> pageList = riskEventMapper.findRiskIPListsByPage(params, new PageBounds(params.getInt("page"), params.getInt("pageSize")));
        return new Page(pageList);
    }

    //=====================yyangs end====================


}
